﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace JControlEx.Common
{
    /// <summary>
    /// A class that describe the property.
    /// </summary>
    public class MemberProperty
    {
        public MemberProperty(string propertyName)
        {
            PropertyName = propertyName;
            IsHighlight = false;
            IsTriggerSave = null;
            IsDateTime = false;
            IsEditable = true;
            IsFixVertical = false;
            IsPicture = false;
        }

        /// <summary>
        /// Gets or sets the name of the property.
        /// </summary>
        public string PropertyName { get; set; }

        /// <summary>
        /// Gets or sets the display name of the property.
        /// </summary>
        public string DisplayName { get; set; }

        /// <summary>
        /// Gets or sets a boolean value that indicates whether the property be highlighted.
        /// </summary>
        public bool IsHighlight { get; set; }

        /// <summary>
        /// Gets or sets a boolean value that indicates whether the value of property changed will trigger save button.
        /// <para>
        /// Defaults is null.
        /// </para>
        /// <para>
        /// If the type is not a collection, regards as false. 
        /// If the type is a collection, regards as true.
        /// </para>
        /// </summary>
        public bool? IsTriggerSave { get; set; }

        /// <summary>
        /// Gets or sets extra data related to this property.
        /// </summary>
        public object Tag { get; set; }

        /// <summary>
        /// Gets or sets a value that indicate whether it is a datetime.
        /// </summary>
        public bool IsDateTime { get; set; }

        /// <summary>
        /// Gets or sets a bool value indicates whether the property is editable.
        /// </summary>
        public bool IsEditable { get; set; }

        /// <summary>
        /// Gets or sets a delegate used for validate the value of the property.
        /// </summary>
        public Func<object, bool> ValidateValue { get; set; }

        /// <summary>
        /// Gets or sets a bool value indicates whether the vertical is sizable.
        /// </summary>
        public bool IsFixVertical { get; set; }

        /// <summary>
        /// Gets or sets a bool value indicates if the byte[] value is a picture.
        /// </summary>
        public bool IsPicture { get; set; }
    }

    public class ObjectToPanelConfiguration
    {
        private static ObjectToPanelConfiguration _instance = null;
        public static ObjectToPanelConfiguration Instance
        {
            get
            {
                if (_instance == null)
                {
                    _instance = new ObjectToPanelConfiguration();
                }
                return _instance;
            }
        }

        public Dictionary<Type, IList<MemberProperty>> MemberPropertyCache { get; set; }

    }

    public static class DictionayExtension
    {
        public static TValue GetValue<TKey, TValue>(this IDictionary<TKey, TValue> dic, TKey key, TValue defaultValue = default(TValue))
        {
            dic.TryGetValue(key, out defaultValue);
            return defaultValue;
        }

        public static void Validate<T>(this T dic) where T : Dictionary<Type, IList<MemberProperty>>
        {
            bool success = true;
            string message = "";
            foreach (Type item in dic.Keys)
            {
                List<string> propertyList = item.GetProperties().Where(p => p.GetCustomAttributes(typeof(System.Xml.Serialization.XmlIgnoreAttribute), false).Count() == 0).Select(p => p.Name).ToList();
                List<string> configedProp = dic[item].Select(mem => mem.PropertyName).ToList();
                IEnumerable<string> intersectProp = configedProp.Intersect(propertyList);
                success = new List<string>(intersectProp).Count == propertyList.Count;
                if (!success)
                {
                    message += item.Name + ": " + string.Join(",", propertyList.Except(intersectProp).ToArray()) + Environment.NewLine;
                    message += "Data Models: " + string.Join(",", configedProp.Except(intersectProp).ToArray()) + Environment.NewLine;
                }
            }

            if (!string.IsNullOrEmpty(message))
            {
                throw new FormatException(message);
            }
        }
    }
}
